import pygame
from pygame.locals import *
from typing import Dict, List, Tuple
from levels import LEVELS
from save import save_progress, load_progress
import os
import json

class ResourceManager:
    """管理游戏资源"""
    def __init__(self):
        self.images: Dict[str, pygame.Surface] = {}
        self.fonts: Dict[str, pygame.font.Font] = {}
        
    def load_image(self, name: str, path: str) -> pygame.Surface:
        """加载图像资源并缩放至64x64"""
        try:
            image = pygame.image.load(path).convert_alpha()
            image = pygame.transform.scale(image, (64, 64))  # 缩放图片
            self.images[name] = image
            return image
        except Exception as e:
            print(f"加载图片 {path} 失败: {str(e)}")
            # 回退到纯色块
            surface = pygame.Surface((64, 64))
            surface.fill((255, 0, 0))  # 红色表示加载失败
            return surface
        
    def load_font(self, name: str, font_name: str, size: int, is_system_font=True) -> pygame.font.Font:
        """加载字体资源"""
        if is_system_font:
            font = pygame.font.SysFont(font_name, size)
        else:
            font = pygame.font.Font(font_name, size)
        self.fonts[name] = font
        return font

    def load_chinese_font(self, name: str, size: int) -> pygame.font.Font:
        """加载中文字体"""
        # Try loading from system fonts first
        try:
            return self.load_font(name, 'SimHei', size, is_system_font=True)
        except:
            # Fallback to local font file
            font_path = os.path.join('assets', 'fonts', 'SimHei.ttf')
            return self.load_font(name, font_path, size, is_system_font=False)
        
    def get_image(self, name: str) -> pygame.Surface:
        """获取已加载的图像"""
        return self.images.get(name)
        
    def get_font(self, name: str) -> pygame.font.Font:
        """获取已加载的字体"""
        return self.fonts.get(name)
        
    def release_resources(self):
        """释放所有资源"""
        self.images.clear()
        self.fonts.clear()

class SoundManager:
    def __init__(self):
        self.sounds = {}
        self.music_playing = False
        self.volume = 0.5  # 默认音量
        
    def load_sounds(self):
        """加载音效资源"""
        sound_files = {
            'move': 'move.wav',
            'push': 'push.wav', 
            'complete': 'complete.wav'
        }
        
        for name, filename in sound_files.items():
            try:
                path = os.path.join('sounds', filename)
                if not os.path.exists(path):
                    print(f"警告：音效文件 {filename} 不存在")
                    continue
                    
                sound = pygame.mixer.Sound(path)
                sound.set_volume(self.volume)
                self.sounds[name] = sound
            except Exception as e:
                print(f"加载音效 {filename} 失败: {str(e)}")
                
        return len(self.sounds) == len(sound_files)  # 返回是否所有音效加载成功
            
    def play_music(self):
        """播放背景音乐"""
        try:
            path = os.path.join('sounds', 'bgm.mp3')
            if not os.path.exists(path):
                print("警告：背景音乐文件不存在")
                return False
                
            pygame.mixer.music.load(path)
            pygame.mixer.music.set_volume(self.volume)
            pygame.mixer.music.play(-1)  # 循环播放
            self.music_playing = True
            return True
        except Exception as e:
            print(f"播放背景音乐失败: {str(e)}")
            return False
            
    def play_sound(self, name):
        """播放指定音效"""
        if name not in self.sounds:
            print(f"警告：音效 {name} 未加载")
            return False
            
        self.sounds[name].play()
        return True
        
    def set_volume(self, volume):
        """设置音量（0.0-1.0）"""
        self.volume = max(0.0, min(1.0, volume))
        pygame.mixer.music.set_volume(self.volume)
        for sound in self.sounds.values():
            sound.set_volume(self.volume)

class Game:
    """游戏主类"""
    def __init__(self):
        self.screen = pygame.display.set_mode((1024, 768))  # 调整窗口大小
        self.clock = pygame.time.Clock()
        self.resource_manager = ResourceManager()
        self.sound_manager = SoundManager()
        self.current_level = 1
        self.progress = load_progress()
        self.verify_progress()  # 验证并修复进度数据
        self.level_start_time = 0  # 关卡开始时间
        self.show_level_select = True  # 是否显示关卡选择界面

    def verify_progress(self):
        """验证并修复进度数据"""
        # 确保所有关卡都有记录
        for i in range(1, len(LEVELS)+1):
            level_key = str(i)
            if level_key not in self.progress['levels']:
                self.progress['levels'][level_key] = {
                    'completed': False,
                    'time': 0,
                    'move_count': 0
                }
        
        # 确保current_level在有效范围内
        self.current_level = min(max(1, self.progress['current_level']), len(LEVELS))
        self.progress['current_level'] = self.current_level
        
        # 确保total_moves存在且有效
        if 'total_moves' not in self.progress:
            self.progress['total_moves'] = sum(
                level['move_count'] for level in self.progress['levels'].values()
            )
        
        # 加载图片资源
        self.resource_manager.load_image('wall', 'assets/images/walls.png')
        self.resource_manager.load_image('box', 'assets/images/boxes.png')
        self.resource_manager.load_image('player', 'assets/images/player.png')
        self.resource_manager.load_image('target', 'assets/images/targets.png')
        
    def run(self):
        """运行游戏主循环"""
        pygame.display.set_caption("推箱子游戏")
        self.sound_manager.load_sounds()
        self.sound_manager.play_music()
        
        # 显示关卡选择界面
        if self.show_level_select:
            self.show_level_select_menu()
        
        # 加载当前关卡
        self.load_level(self.current_level)
        
        running = True
        while running:
            for event in pygame.event.get():
                if event.type == QUIT:
                    # 退出前保存进度
                    save_progress(self.progress)
                    running = False
                elif event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        if self.show_pause_menu():
                            # 从暂停菜单返回后保存进度
                            save_progress(self.progress)
                    elif event.key == K_r:  # 重置当前关卡
                        self.reset_level()
                    elif event.key == K_s:  # 显示关卡选择
                        self.show_level_select_menu()
                    elif event.key in (K_UP, K_DOWN, K_LEFT, K_RIGHT):
                        self.handle_move(event.key)
                        
            # 渲染游戏
            self.render()
            pygame.display.flip()
            self.clock.tick(60)
            
            # 检查是否完成当前关卡
            if self.check_level_complete():
                self.sound_manager.play_sound('complete')
                # 计算关卡完成时间（秒）
                level_time = (pygame.time.get_ticks() - self.level_start_time) // 1000
                self.progress['levels'][str(self.current_level)]['completed'] = True
                self.progress['levels'][str(self.current_level)]['time'] = level_time
                
                # 保存进度
                save_progress(self.progress)
                
                # 显示完成提示
                self.show_level_complete_screen(level_time)
                
                # 显示完成提示
                if self.current_level == len(LEVELS):
                    self.show_all_levels_complete_screen()
                    self.show_level_select_menu()
                else:
                    # 加载下一关
                    self.current_level += 1
                    self.progress['current_level'] = self.current_level
                    self.load_level(self.current_level)
                    save_progress(self.progress)  # 保存关卡切换进度
                    
        pygame.quit()
        
    def show_level_select_menu(self):
        """显示关卡选择界面"""
        menu_font = self.resource_manager.load_chinese_font('menu', 48)
        title_font = self.resource_manager.load_chinese_font('title', 64)
        
        while True:
            self.screen.fill((0, 0, 0))
            
            # 绘制标题
            title_text = title_font.render('选择关卡', True, (255, 255, 255))
            self.screen.blit(title_text, (1024//2 - title_text.get_width()//2, 50))
            
            # 绘制关卡按钮
            button_width = 200
            button_height = 80
            margin = 20
            start_x = (1024 - (4 * button_width + 3 * margin)) // 2
            start_y = 200
            
            for i in range(len(LEVELS)):
                level_num = i + 1
                x = start_x + (i % 4) * (button_width + margin)
                y = start_y + (i // 4) * (button_height + margin)
                
                # 绘制按钮背景
                color = (0, 128, 255) if self.progress['levels'][str(level_num)]['completed'] else (64, 64, 64)
                pygame.draw.rect(self.screen, color, (x, y, button_width, button_height))
                
                # 绘制关卡编号
                level_text = menu_font.render(f'关卡 {level_num}', True, (255, 255, 255))
                self.screen.blit(level_text, (x + button_width//2 - level_text.get_width()//2,
                                            y + button_height//2 - level_text.get_height()//2))
            
            pygame.display.flip()
            
            # 处理事件
            for event in pygame.event.get():
                if event.type == QUIT:
                    save_progress(self.progress)
                    pygame.quit()
                    return
                elif event.type == MOUSEBUTTONDOWN:
                    # 检查点击了哪个关卡
                    mouse_x, mouse_y = pygame.mouse.get_pos()
                    for i in range(len(LEVELS)):
                        level_num = i + 1
                        x = start_x + (i % 4) * (button_width + margin)
                        y = start_y + (i // 4) * (button_height + margin)
                        
                        if x <= mouse_x <= x + button_width and y <= mouse_y <= y + button_height:
                            self.current_level = level_num
                            self.progress['current_level'] = level_num
                            self.load_level(level_num)
                            self.show_level_select = False
                            return
                elif event.type == KEYDOWN and event.key == K_ESCAPE:
                    self.show_level_select = False
                    return

    def reset_level(self):
        """重置当前关卡"""
        self.load_level(self.current_level)
        self.progress['levels'][str(self.current_level)]['move_count'] = 0
        self.progress['total_moves'] -= self.progress['levels'][str(self.current_level)]['move_count']
        save_progress(self.progress)
        
    def load_level(self, level_index: int):
        """加载指定关卡"""
        if level_index < 1 or level_index > len(LEVELS):
            raise ValueError("无效的关卡索引")
            
        # 释放上一关的资源
        self.resource_manager.release_resources()
        
        # 加载新关卡
        self.level = LEVELS[level_index-1]
        self.player_pos = self.level.player
        self.boxes = self.level.boxes.copy()
        self.level_start_time = pygame.time.get_ticks()  # 记录关卡开始时间
        
        # 重新加载资源
        self.resource_manager.load_image('wall', 'assets/images/walls.png')
        self.resource_manager.load_image('box', 'assets/images/boxes.png')
        self.resource_manager.load_image('player', 'assets/images/player.png')
        self.resource_manager.load_image('target', 'assets/images/targets.png')
        
    def handle_move(self, direction: int):
        """处理玩家移动"""
        dx, dy = 0, 0
        if direction == K_UP:
            dy = -1
        elif direction == K_DOWN:
            dy = 1
        elif direction == K_LEFT:
            dx = -1
        elif direction == K_RIGHT:
            dx = 1
            
        new_x = self.player_pos[0] + dx
        new_y = self.player_pos[1] + dy
        
        # 检查新位置是否合法
        if (new_x, new_y) in self.level.walls:
            return
            
        # 检查是否推动箱子
        if (new_x, new_y) in self.boxes:
            box_new_x = new_x + dx
            box_new_y = new_y + dy
            if (box_new_x, box_new_y) in self.level.walls or (box_new_x, box_new_y) in self.boxes:
                return
            self.boxes.remove((new_x, new_y))
            self.boxes.append((box_new_x, box_new_y))
            self.sound_manager.play_sound('push')
        else:
            self.sound_manager.play_sound('move')
            
        self.player_pos = (new_x, new_y)
        self.progress['total_moves'] += 1
        # 确保move_count被初始化
        if 'move_count' not in self.progress['levels'][str(self.current_level)]:
            self.progress['levels'][str(self.current_level)]['move_count'] = 0
        self.progress['levels'][str(self.current_level)]['move_count'] += 1
        
    def check_level_complete(self) -> bool:
        """检查当前关卡是否完成"""
        completed = all(box in self.level.targets for box in self.boxes)
        if completed:
            # 确保完成时间被记录
            level_time = (pygame.time.get_ticks() - self.level_start_time) // 1000
            self.progress['levels'][str(self.current_level)]['time'] = level_time
            # 确保完成状态被记录
            self.progress['levels'][str(self.current_level)]['completed'] = True
        return completed
        
    def show_level_complete_screen(self, time: int):
        """显示关卡完成界面"""
        font = self.resource_manager.load_chinese_font('menu', 48)
        complete_text = font.render('关卡完成！', True, (255, 255, 255))
        time_text = font.render(f'用时: {time}秒', True, (255, 255, 255))
        next_text = font.render('按任意键继续下一关', True, (255, 255, 255))
        
        # 创建半透明背景
        overlay = pygame.Surface((1024, 768), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 128))
        self.screen.blit(overlay, (0, 0))
        
        # 绘制文本
        self.screen.blit(complete_text, (1024//2 - complete_text.get_width()//2, 200))
        self.screen.blit(time_text, (1024//2 - time_text.get_width()//2, 300))
        self.screen.blit(next_text, (1024//2 - next_text.get_width()//2, 400))
        pygame.display.flip()
        
        # 等待用户按键
        waiting = True
        while waiting:
            for event in pygame.event.get():
                if event.type == KEYDOWN:
                    waiting = False
                elif event.type == QUIT:
                    return False
        return True

    def show_all_levels_complete_screen(self):
        """显示所有关卡完成界面"""
        font = self.resource_manager.load_chinese_font('menu', 48)
        title_font = self.resource_manager.load_chinese_font('title', 64)
        
        # 创建半透明背景
        overlay = pygame.Surface((1024, 768), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 128))
        self.screen.blit(overlay, (0, 0))
        
        # 绘制标题
        title_text = title_font.render('恭喜！', True, (255, 255, 255))
        self.screen.blit(title_text, (1024//2 - title_text.get_width()//2, 200))
        
        # 绘制提示信息
        complete_text = font.render('您已完成所有关卡！', True, (255, 255, 255))
        self.screen.blit(complete_text, (1024//2 - complete_text.get_width()//2, 300))
        
        next_text = font.render('按任意键返回主菜单', True, (255, 255, 255))
        self.screen.blit(next_text, (1024//2 - next_text.get_width()//2, 400))
        
        pygame.display.flip()
        
        # 等待用户按键
        waiting = True
        while waiting:
            for event in pygame.event.get():
                if event.type == KEYDOWN:
                    waiting = False
                elif event.type == QUIT:
                    return False
        return True

    def show_pause_menu(self):
        """显示暂停菜单"""
        menu_font = self.resource_manager.load_chinese_font('menu', 48)
        menu_text = menu_font.render('游戏暂停', True, (255, 255, 255))
        continue_text = menu_font.render('按ESC继续游戏', True, (255, 255, 255))
        reset_text = menu_font.render('按R重置当前关卡', True, (255, 255, 255))
        select_text = menu_font.render('按S选择关卡', True, (255, 255, 255))
        
        # 创建半透明背景
        overlay = pygame.Surface((1024, 768), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 128))
        self.screen.blit(overlay, (0, 0))
        
        # 绘制菜单文本
        self.screen.blit(menu_text, (1024//2 - menu_text.get_width()//2, 200))
        self.screen.blit(continue_text, (1024//2 - continue_text.get_width()//2, 300))
        self.screen.blit(reset_text, (1024//2 - reset_text.get_width()//2, 400))
        self.screen.blit(select_text, (1024//2 - select_text.get_width()//2, 500))
        pygame.display.flip()
        
        # 等待用户输入
        paused = True
        while paused:
            for event in pygame.event.get():
                if event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        paused = False
                    elif event.key == K_r:  # 重置当前关卡
                        self.reset_level()
                        paused = False
                    elif event.key == K_s:  # 显示关卡选择
                        self.show_level_select_menu()
                        paused = False
                elif event.type == QUIT:
                    return False
        return True

    def render(self):
        """渲染游戏画面"""
        self.screen.fill((0, 0, 0))
        
        # 渲染墙壁
        wall_img = self.resource_manager.get_image('wall')
        for x, y in self.level.walls:
            self.screen.blit(wall_img, (x*64, y*64))  # 调整显示位置
            
        # 渲染目标点
        target_img = self.resource_manager.get_image('target')
        for x, y in self.level.targets:
            self.screen.blit(target_img, (x*64, y*64))  # 调整显示位置
            
        # 渲染箱子
        box_img = self.resource_manager.get_image('box')
        for x, y in self.boxes:
            self.screen.blit(box_img, (x*64, y*64))  # 调整显示位置
            
        # 渲染玩家
        player_img = self.resource_manager.get_image('player')
        x, y = self.player_pos
        self.screen.blit(player_img, (x*64, y*64))  # 调整显示位置
        
def main():
    """游戏主函数"""
    pygame.init()
    game = Game()
    game.run()

if __name__ == "__main__":
    main()
